package ferp.android.tasks.local;

import ferp.android.activities.Ferp;
import ferp.android.services.IResolverService2;
import ferp.android.services.ServiceException;
import ferp.android.services.ServiceProxy;
import ferp.core.ai.tree2.Score;
import ferp.core.card.Card;
import ferp.core.game.*;
import ferp.core.mode.Mode;
import ferp.core.player.Hand;
import ferp.core.player.Player;

/**
 * User: olegs
 * Date: 4/3/13 6:44 PM
 */
public class TaskTrickingTenCheck extends TaskSerial<Void, ServiceException>
{
  public TaskTrickingTenCheck(Ferp ferp, Game game, Settings settings, IResolverService2 service)
  {
    super(ferp);

    this.game     = game;
    this.settings = settings;
    this.service  = service;
  }

  @Override
  protected void onPreExecute()
  {
    ferp().onTrickingTenCheckStarted(game);
  }

  @Override
  protected ServiceException doInBackground(Void... voids)
  {
    try
    {
      // initializer the resolver
      ServiceProxy.initialize(service, game, settings);
      // solve the game
      solve();

      return null;
    }
    catch (ServiceException e)
    {
      return e;
    }
  }

  @Override
  protected void doOnPostExecute(ServiceException e)
  {
    if (e == null)
    {
      game.options.clear();

      if (tricks[game.player.declarer] == Game.MAXIMUM_TRICKS)
      {
        game.setTricks(game.player.declarer, Game.MAXIMUM_TRICKS);
        // switch to Score state
        game.score();
      }
      else
      {
        // reset the mode to 'Tricking10' to start from 'Initialize' state
        game.set(Mode.tricking10);

        Player p1 = game.previous(game.declarer());
        Player p2 = game.next(game.declarer());

        game.setBid(p1.id(), Bid.check(tricks[p1.id()]), null);
        game.setBid(p2.id(), Bid.check(tricks[p2.id()]), null);

        ferp().onPlayerContract(p1, game.getBid(p1.id()));
        ferp().onPlayerContract(p2, game.getBid(p2.id()));
      }

      ferp().onTrickingTenCheckFinished(game);
    }
    else
      ferp().exit(e);
  }

  private void solve() throws ServiceException
  {
    int hands[] = new int[Game.PLAYERS];
    boolean complete = false;

    for (Player p : game.players())
      hands[p.id()] = game.getHand(p.id()).current;

    int starting = Game.next(game.player.dealer);

    while (!complete && !isCancelled())
    {
      int hand = 0;
      int trick = 0;
      short score = 0;

      // make moves
      for (int id = starting; Trick.size(trick) < Game.PLAYERS; id = Game.next(id), ++hand)
      {
        ServiceProxy.solve(service);

        score = (short)ServiceProxy.getBestScore(service);

        // make the move according to AI level
        int depth = Levels.getBestMoveDepth(game, settings, game.player(id));
        byte move = ServiceProxy.getBestMove(service, depth, hand, trick, hands[id]);

        // update current player's hand and game trick
        hands[id] = Hand.remove(hands[id], Card.card(move).hash);
        trick = Trick.add(trick, id, move);

        // advance
        ServiceProxy.advance(service, hand, trick);
      }

      complete = Score.isComplete(score);

      if (complete)
      {
        // tree is complete - finalize tricks
        for (int id = 0; id < Game.PLAYERS; ++id)
          tricks[id] += Score.get(score, id);
      }
      else
      {
        starting = Trick.winner(trick, game.trump());
        ++tricks[starting];
      }
    }
  }

  private final Game game;
  private final Settings settings;
  private final IResolverService2 service;
  private final int[] tricks = new int[Game.PLAYERS];
}
